// object 
const objectFactory = function () {
    const obj = new Object();
    Constructor = [].shift.call(arguments);
    obj.__proto__ = Constructor.prototype;
    const ret = Constructor.apply(obj, arguments);
    return typeof ret === 'object' ? ret : obj;
}
// bind function 模拟
Function.prototype.bind ? Function.prototype.bind : Function.prototype.bind = function () {
    // const self = this;
    // return function () {
    //     return self.apply(context, arguments)
    // }
    const self = this;
    const context = [].shift.apply(arguments);
    const arg = [].slice.apply(arguments);
    return function () {
        return self.apply(context, [].concat.call(args, [].slice.call(arguments)));
    }
}
// 闭包获取元素循环，可以使用块级作用域来解决
for (let i = 0, len = 10; i < len; i++) {
    (function (i) {
        console.log(i)
    })(i)
}

{ // 如果是在dom元素中能不能直接使用？
    for(let i = 0, len = 5; i < len; i++) {
        console.log(i)
    }
}
// 使用闭包乘积计算
const mult = (() => {
    let cache = {};
    function calculate () {
        let a = 1;
        for (let i = 1, l = arguments.length; i < l; i++) {
            a = a * arguments[i];
        }

        return a;
    }

    return function () {
       const args = Array.prototype.join.call(arguments, ',');
       if (args in cache) {
           return cache[args];
       }

       return cache[args] = calculate.apply(null, arguments);
    }
})();

console.log(mult(1, 4, 5, 7))

export function isString(obj) {
    return Object.prototype.toString.call(obj) === '[object String]'
}

export function isNumber(obj) {
    return Object.prototype.toString.call(obj) === '[object Number]'
}

export function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]'
}

export function isType(type) {
    return function (obj) {
        return Object.prototype.toString.call(obj) === `[Object ${type}]`
    }
}

// 单例模式
const Singleton = function (name) {
    this.name = name;
    this.instance = null;
}

Singleton.prototype.getName = function () {
    console.log(this.name)
    return this.name
}

Singleton.getInstance = function (name) {
    if (!this.instance) {
        this.instance = new Singleton(name)
    }
    return this.instance
}

function Singleton2 (name) {
    this.name = name
}

Singleton2.prototype.getName = function () {
    console.log(this.name)
    return this.name
}

Singleton2.getInstance = (function () {
    let instance = null
    return function (name) {
        if (!instance) {
            instance = new Singleton2(name)
        }
        return instance
    }
})()

const a = new Singleton2.getInstance('sevens')
console.log(a.getName())

const PerformanceS = function () {}
PerformanceS.prototype.calculate = function (salary) {
    return salary * 4;
}

function PerformanceA () {}
PerformanceA.prototype.calculate = function (salary) {
    return salary * 3;
}
function PerformanceB () {}
PerformanceB.prototype.calculate = function (salary) {
    return salary * 2;
}

function Bouns () {
    this.salary = null;
    this.strategy = null
}
Bouns.prototype.setSalary = function (salary) {
    this.salary = salary
}
Bouns.prototype.setStrategy = function (strategy) {
    this.strategy = strategy
}
Bouns.prototype.getBouns = function () {
    return this.strategy.calculate(this.salary)
}

const bouns = new Bouns()
bouns.setSalary(1000)
bouns.setStrategy(new PerformanceS())
console.log(bouns.getBouns())

function calculateBouns () {
    return this.strategy['level']()
}